﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace ModelPredictPro.General.IO {
    public static class FileHelper {
        /// <summary>
        /// 按行合并文件
        /// </summary>
        public static void ImergeFiles(string outputFileName, params string[] sourceFiles) {
            if (sourceFiles == null || sourceFiles.Length == 0) return;

            using (StreamWriter writer = new StreamWriter(outputFileName)) {
                foreach (string item in sourceFiles) {
                    foreach (string line in FileReader.ReadAllLines(item)) {
                        writer.WriteLine(line);
                    }
                }
            }
        }
        /// <summary>
        /// 按正负集产生 N Fold 文件
        /// </summary>
        /// <param name="positiveSet">正集数据集</param>
        /// <param name="negativeSet">负集数据集</param>
        /// <param name="nfold">n-fold次数</param>
        public static void GenerateNFoldFiles(string positiveSet, string negativeSet, int nfold, ref string[]outputTrainFiles, ref string []outputTestFiles) {
            FileInfo[] posFiles = DivideToNFiles(positiveSet, nfold);
            // 允许传入空的负集文件，用于多类的 N-Fold （不指定负集）
            FileInfo[] negativeFiles =null;
            if (!string.IsNullOrEmpty(negativeSet))
                negativeFiles = DivideToNFiles(negativeSet, nfold);


            //初始化文件名
            if (outputTrainFiles == null || outputTrainFiles.Length != nfold)
                outputTrainFiles = GenerateRandomFiles(nfold).Select(o=>o.FullName).ToArray();
            if (outputTestFiles == null || outputTestFiles.Length != nfold)
                outputTestFiles = GenerateRandomFiles(nfold).Select(o => o.FullName).ToArray();

            for (int i = nfold -1; i >=0; i--) {
                List<string> trainSources = new List<string>();
                List<string> testSources = new List<string>();
                for (int j = 0; j < nfold; j++) {
                    if (j == i) {
                        testSources.Add(posFiles[j].FullName);
                        continue;
                    }
                    trainSources.Add(posFiles[j].FullName);
                }
                if (!string.IsNullOrEmpty(negativeSet)) {
                    for (int j = 0; j < nfold; j++) {
                        if (j == i) {
                            testSources.Add(negativeFiles[j].FullName);
                            continue;
                        }
                        trainSources.Add(negativeFiles[j].FullName);
                    }
                }
                ImergeFiles(outputTrainFiles[nfold - i - 1], trainSources.ToArray());
                ImergeFiles(outputTestFiles[nfold - i - 1], testSources.ToArray());
            }
            // 删除用到的临时文件 
            if (!string.IsNullOrEmpty(negativeSet))
                posFiles.Union(negativeFiles).ToList().ForEach(o => o.Delete());
            else
                posFiles.ToList().ForEach(o => o.Delete());
        }


        public static FileInfo[] DivideToNFiles(string sourceFile, int nfold) {
            int totalCount = FileReader.GetLineCount(sourceFile);
            if (totalCount < nfold) throw new Exception(string.Format("指定的文件 {0} 所包含的总行数 {1} 小于NFold数 {2}", sourceFile, totalCount, nfold));
            int equalUnit = totalCount / nfold;

            FileInfo[] rst = GenerateRandomFiles(nfold);
            int countIndex = 0;
            StreamWriter writer = null;
            try {
                foreach (string line in FileReader.ReadAllLines(sourceFile)) {
                    if (countIndex % equalUnit == 0 && countIndex/equalUnit < nfold) {
                        if (writer != null) writer.Close();
                        writer = rst[countIndex / equalUnit].CreateText();
                    }
                    writer.WriteLine(line);
                    countIndex++;
                }
            }
            finally {
                if (writer != null) writer.Close();
            }
            return rst;
        }

        internal static string GenerateRandomFilePath() {
            return Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
        }
        internal static FileInfo[] GenerateRandomFiles(int count) {
            FileInfo[] rst = new FileInfo[count];
            for (int i = 0; i < rst.Length; i++) {
                rst[i] = new FileInfo(GenerateRandomFilePath());
            }
            return rst;
        }
        public static string GetDirectory(this string filePath) {
            return new FileInfo(filePath).DirectoryName;
        }
    }
}
